// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html

import GameConfig, { BlockData, COLOR, DIRECTION, ShapeData, ShapeType } from "./GameConfig";
import MapManager from "./map/MapManager";




const {ccclass, property} = cc._decorator;

@ccclass
export default class Utlis {

    public static async loadPrefab(path:string):Promise<cc.Prefab> {
        const prefab:cc.Prefab = await new Promise<cc.Prefab>((resolve)=>{
            cc.resources.load(path, (err, prefab)=>{
                if(err) {
                    console.error(err);
                }
                resolve(prefab);
            })
        })
        return prefab;
    }

    public static createShapeArray(type:ShapeType, angle:number = 0) {
        const shape = GameConfig.SHAPES[type];
        let arr = shape ? shape.map(row => [...row]) : GameConfig.SHAPES.I.map(row => [...row]);
        const row = arr.length;
        const col = arr[0].length;
        const rotateTimes = angle/90;
        if (angle == 0) {
            return arr;
        }
        const ret:number[][] = [];
        for (let i = 0; i < rotateTimes; i++) {
            for (let j = 0;j < row;j++) {
                for (let k = 0;k < col; k++) {
                    if (ret[k] == null) {
                        ret[k] = []
                    }
                    ret[k][row-1-j] = arr[j][k];
                }
            }

            
            arr = ret.map(subArray => subArray.slice());;
        }
        return ret;
    }
    
    public static async createShape(type:ShapeType, color:COLOR) {
        const shapeArray = this.createShapeArray(type);
        let parentNode = new cc.Node("Shape");
        let width = 0;
        let height = shapeArray.length;
        const icon = new cc.Node();
        for (let y = 0; y < shapeArray.length; y++) { 
            if (width < shapeArray[y].length) {
                width = shapeArray[y].length;
            }
            for (let x = 0; x < shapeArray[y].length; x++) {
                if (shapeArray[y][x] != 0) {
                    const prefab = await Utlis.loadPrefab(GameConfig.BIG_BLOCK_PREFAB);
                    const node:cc.Node = cc.instantiate(prefab);
                    const posX = x*GameConfig.BIG_BLOCK_SIZE;
                    const posY = y*GameConfig.BIG_BLOCK_SIZE;
                    node.setPosition(posX, posY);
                    node.color = GameConfig.getColor(color);
                    icon.addChild(node);
                }
            }
        }

        width = width*GameConfig.BIG_BLOCK_SIZE;
        height = height*GameConfig.BIG_BLOCK_SIZE;
        icon.width = width;
        icon.height = height;
        icon.setPosition(-width/2, -height/2);
        parentNode.addChild(icon);
        return parentNode;
    }

    public static writeToBigGrid(shapeData:ShapeData,angle:number = 0) {
        const shapeArray = this.createShapeArray(shapeData.type,angle);

        for (let y = 0; y < shapeArray.length; y++) { 
            for (let x = 0; x < shapeArray[y].length; x++) {
                if (shapeArray[y][x]) {
                    const blockData:BlockData = {
                        x: shapeData.gridPos.x+x,
                        y: shapeData.gridPos.y+y,
                        color: shapeData.color
                    };
                    MapManager.getInstance().setBigBlockData(blockData);
                }
            }
        }
    }

    public static canBlockPass(shapeData:ShapeData,angle:number = 0, direct:DIRECTION = DIRECTION.Down) {
        
        const directPos = cc.Vec2.ZERO;
        switch (direct) {
            case DIRECTION.Down:
                directPos.y = -1;
                break;
            case DIRECTION.Left:
                directPos.x = -1;
                break;
            case DIRECTION.Right:
                directPos.x = 1;
                break;
            case DIRECTION.Up:
                directPos.y = 1;
                break;
        }


        //有障碍物
        const shapeArray = this.createShapeArray(shapeData.type,angle);
        for (let y = 0; y < shapeArray.length; y++) { 
            for (let x = 0; x < shapeArray[y].length; x++) {
                if (shapeArray[y][x] != COLOR.Null) {
                    const gridPos = new cc.Vec2(shapeData.gridPos.x+x, shapeData.gridPos.y+y);
                    const nextGridPos = gridPos.add(directPos);

                    //超出边界
                    if (nextGridPos.y <= GameConfig.BOARD_HEIGHT) {
                        return false;
                    }

                    if (MapManager.getInstance().hasBlockAt(nextGridPos)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public static widgetAdapterFullScene(widget:cc.Widget) {
        widget.isAlignBottom = true;
        widget.isAlignTop = true;
        widget.isAlignLeft = true;
        widget.isAlignRight = true;
        widget.left = 0;
        widget.top = 0;
        widget.bottom = 0;
        widget.right = 0;
        widget.updateAlignment();
    }
}
